package ltd.hyangyang.rpc.core.context;

import lombok.SneakyThrows;
import ltd.hyangyang.rpc.common.bean.RpcConfig;
import ltd.hyangyang.rpc.common.bean.RpcProperties;
import ltd.hyangyang.rpc.common.utils.PropertiesReadUtils;
import ltd.hyangyang.rpc.common.utils.SingletonFactory;
import ltd.hyangyang.rpc.core.anno.ServiceReference;
import ltd.hyangyang.rpc.core.anno.EnableAutoRegistry;
import ltd.hyangyang.rpc.core.provider.ProviderService;
import ltd.hyangyang.rpc.core.provider.impl.ProviderServiceImpl;
import ltd.hyangyang.rpc.core.proxy.ClientProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.logging.Logger;

@Component
public class SpringBeanContext implements BeanPostProcessor {


    private ProviderService providerService;

    private RpcProperties rpcProperties;

    Logger logger = Logger.getGlobal();
    //获取单例Bean
    SpringBeanContext() throws IOException {
        rpcProperties = PropertiesReadUtils.initProperties();
        providerService = SingletonFactory.getSingletonBean(ProviderServiceImpl.class);

    }

    @SneakyThrows
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //在spring中的每个bean初始换之间执行该方法，可以使用该方法判断类中是否有注解，从而判断是否需要使用注册发现的功能
        Class<?> beanClass = bean.getClass();
        EnableAutoRegistry serviceRegistry = beanClass.getDeclaredAnnotation(EnableAutoRegistry.class);
        //如果在类上有这个注解，则表示该服务的具体实现在服务端，使用rpc框架，调用远程方法
        if (!ObjectUtils.isEmpty(serviceRegistry)) {
            //注册发现
            //将所有bean中包含注解@EnableAutoRegistry注解的类的实例保存到ConCurrentHashMap集合中
            String group = serviceRegistry.group();
            String serviceName = serviceRegistry.serviceName();
            if (serviceName.equals("default")){
                serviceName = bean.getClass().getName();
            }
            RpcConfig rpcConfig = RpcConfig
                    .builder()
                    .serviceName(serviceName)
                    .group(group)
                    .build();
            //需要注册到zookeeper中的信息
            providerService.publishService(rpcConfig);

        }
        return bean;
    }

    @SneakyThrows
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //由于注解发在字段上，因此要使用
        Field[] declaredFields = bean.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            ServiceReference serviceReference = declaredField.getAnnotation(ServiceReference.class);
            if (!ObjectUtils.isEmpty(serviceReference)){
                String serviceName = serviceReference.serviceName();
                String group = serviceReference.group();
                RpcConfig rpcConfig = RpcConfig.builder()
                        .serviceName(serviceName)
                        .group(group)
                        .build();
                ClientProxyFactory clientProxyFactory = new ClientProxyFactory(rpcConfig);
                Object proxy = clientProxyFactory.getProxy(declaredField.getType());
                //将spring容器中的Bean替换成proxy
                //为了对类中的参数进行修改，取消安全安全检查
                declaredField.setAccessible(true);
                if (!ObjectUtils.isEmpty(proxy)){
                    //将实例bean中的declaredField这个字段的值替换成proxy
                    declaredField.set(bean,proxy);
                }
            }
        }

        return bean;
    }
}
